import axios from 'axios'
import store from '@/store'
import { Message } from 'element-ui'
import router from '@/router'
import qs from 'qs'
const request = axios.create({})

// 请求拦截器
request.interceptors.request.use(
  config => {
    // console.log('请求拦截器', config)

    // 通过改写 config 配置信息来实现业务功能的统一处理
    const { user } = store.state
    if (user && user.access_token) {
      config.headers.Authorization = user.access_token
    }

    // 注意： 这里一定要返回 config，否则请求就发不出去了
    return config
  },
  error => {
    return Promise.reject(error)
  }
)
function redirectLogin() {
  router.push({
    name: 'login',
    query: {
      redirect: router.currentRoute.fullPath
    }
  })
}
function refreshToken() {
  return axios.create()({
    method: 'POST',
    url: '/front/user/refresh_token',
    data: qs.stringify({
      refreshtoken: store.state.user.refresh_token
    })
  })
}
// 响应拦截器
let isRefreshing = false // 标记是否正在刷新 token， false 表示未在刷新 token， true表示正在刷新 token
let requests: Function[] = [] // 用来存储刷新 token 期间过来的 401 请求
request.interceptors.response.use(
  response => {
    // 状态码为 2xx 都会进入这里
    // 如果是自定义错误状态码， 错误处理就写到这里
    // console.log('响应成功了', response)
    return response
  },
  async error => {
    // 超出 2xx 状态码 都会执行这里
    // 如果是使用 HTTP状态码，错误处理就写到这里
    if (error.response) {
      // 请求发出去收到响应了，但是状态码超出了 2xx 范围
      const { status } = error.response
      if (status === 400) {
        Message.error('请求参数错误')
      } else if (status === 401) {
        // token 无效（没有提供 token、token 无效、 token过期）
        // 如果有 refresh_token 则尝试使用 refresh_token 获取新的 access_token
        // 没有 refresh_token， 则直接跳转到登录页
        if (!store.state.user) {
          // 没有 refresh_token， 则直接跳转到登录页
          redirectLogin()
          return Promise.reject(error)
        }
        if (!isRefreshing) {
          // 没有在刷新 token
          isRefreshing = true // 防止重复刷新 token

          // 有 refresh_token，尝试刷新获取新的 token
          // 需要把结果 return 出去， 请求的数据才能拿到
          return refreshToken()
            .then(res => {
              if (res.data.success) {
                // 成功了 ——> 把本次失败的请求重新发出去
                // 把刷新拿到的新的 access_token 更新到容器和本地存储中
                store.commit('setUser', res.data.content)
                // 把刷新 token 期间过来的 401 请求重新发出去
                requests.forEach(cb => cb())
                requests = []
                // 把本次失败的请求发出去
                return request(error.config)
              } else {
                throw new Error('刷新token失败')
              }
            })
            .catch(err => {
              // 失败了 ——> 跳转登录页
              store.commit('setUser', null)
              redirectLogin()
              return Promise.reject(err)
            })
            .finally(() => {
              isRefreshing = false
            })
        }
        // 刷新 token 期间过来的 401 请求通过 promise 挂起, 放入一个队列中，等刷新 token 成功之后再把 request 队列中请求发送出去
        return new Promise(resolve => {
          requests.push(() => {
            resolve(request(error.config))
          })
        })
        // 有 refresh_token，尝试刷新获取新的 token
        // try {
        //   // 无法捕获自定义错误，多次请求会多次刷新token
        //   // 由于refreshtoken 只能使用1次，多次刷新会导致获取token失败，接口返回的是自定义错误 try catch 并没有捕获到
        //   // 所以多次刷新 token 之后容器和本地存储中用户信息被更新为null，重新发出去的请求变为401， 由于用户信息不存在，所以直接跳转到了登录页
        //   const { data } = await axios.create()({
        //     method: 'POST',
        //     url: '/front/user/refresh_token',
        //     data: qs.stringify({
        //       refreshtoken: store.state.user.refresh_token
        //     })
        //   })
        //   // 成功了 ——> 把本次失败的请求重新发出去
        //   // 把刷新拿到的新的 access_token 更新到容器和本地存储中
        //   store.commit('setUser', data.content)
        //   // 把本次失败的请求发出去
        //   return request(error.config)
        // } catch (err) {
        //   // 失败了 ——> 跳转登录页
        //   store.commit('setUser', null)
        //   redirectLogin()
        //   return Promise.reject(error)
        // }
      } else if (status === 403) {
        Message.error('没有权限，请联系管理员')
      } else if (status === 404) {
        Message.error('请求资源不存在')
      } else if (status >= 500) {
        Message.error('服务端错误，请联系管理员')
      }
    } else if (error.request) {
      // 请求发出去没有收到响应
      console.log(error.request)
      Message.error('请求超时，请刷新重试')
    } else {
      // 在设置请求时发生了一些事情，触发了一个错误
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message)
      Message.error(`请求失败：${error.message}`)
    }
    return Promise.reject(error)
  }
)
export default request
